home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / DocShell / DraftWn.cpp < prev    next >
Encoding:
Text File  |  1996-04-22  |  49.6 KB  |  1,705 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DraftWn.cpp
  3.  
  4.     Contains:    Implementation of the DraftWin and DraftInfoRec classes
  5.  
  6.     Owned by:    Eric House
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <53>     11/2/95    eeh        1282521: save and restore port in ::Drafts
  13.         <52>    10/18/95    eeh        1293420: wrap TRY around callbacks
  14.         <51>     4/10/95    NP        1287722: Change signature of
  15.                                     ODSession::GetUserName.
  16.         <50>     9/29/95    eeh        1287262: fix constant
  17.         <49>     9/13/95    TÇ        1249149 FB2: Memory leak/crash fixes
  18.         <48>     9/12/95    DM        1280020 FB1 part trans dlg mem leaks
  19.         <47>     9/12/95    eeh        1230007: atTopLeft -> atNone
  20.         <46>      9/8/95    TÇ        1252120 FB1: New documents saved w/ StdFile
  21.                                     & trashed if closed w/o saving
  22.         <45>      9/8/95    TÇ        1281096 FB2:Many constants in ODTypesB
  23.                                     without kOD prefix!
  24.         <44>      9/8/95    TÇ        1282092 FB2: Shell must check nil after SOM
  25.                                     new
  26.         <43>      9/7/95    EL        1281410, 1279985: DeleteSelectedDraft will
  27.                                     close and open the draft above it if it is
  28.                                     open, and rename all the windows for draft
  29.                                     above the seletected draft.
  30.         <42>      9/5/95    TÇ        FBs: 1266428, 1274419, 1274421, 1274423,
  31.                                     1274429, 1274435 Fixed the Shell to handle
  32.                                     multiple documents in a process. Needed for
  33.                                     CyberDog.
  34.         <41>     8/25/95    eeh        1230007: cleanup/proofing
  35.         <40>     8/25/95    eeh        1230007: mondo changes (incomplete)
  36.         <39>     8/22/95    eeh        1230007: use tempobjs for exception safety
  37.         <38>     8/16/95    eeh        1248265: close dialog on mousedown not *up
  38.         <37>      8/3/95    eeh        1229960: use CheckKeyScriptChangeFilterProc
  39.                                     and DialogScriptData
  40.         <36>     7/21/95    eeh        1236744: add CheckDeleteKeyFilterProc;
  41.                                     1263063: call SetPlatformClipboard
  42.         <35>     7/18/95    eeh        1222282: deal with enter key etc. in
  43.                                     DraftDlgFilterProc
  44.         <34>     7/18/95    eeh        1222282 (partial): add DeleteDlgFilterProc,
  45.                                     arrow keys etc.
  46.         <33>     6/25/95    TÇ        1242642 BB: Turn on ODDebug warning if
  47.                                     refcount is wrong in
  48.                                     ODRefCntObjectsomUninit.
  49.         <32>     6/20/95    eeh        1259193: don't return kDraftWinOpen if
  50.                                     selection empty
  51.         <31>     5/26/95    RR        #1251403: Multithreading naming support
  52.         <30>     5/25/95    jpa        Fixed 'for' loop for ANSI compliance.
  53.                                     [1253324] GetScript --> GetScriptVariable.
  54.                                     [1241078]
  55.         <29>     5/22/95    eeh        1245226: disable non-roman scripts if roman
  56.                                     text
  57.         <28>     5/20/95    eeh        1245226: call SetupDialogForAppScript
  58.         <27>     5/18/95    eeh        1236414: disable Delete and Save Draft
  59.                                     buttons for r/o files
  60.         <26>     5/12/95    eeh        1239830: call ODHaveFreeSpace
  61.         <25>     5/10/95    eeh        1215536: remove DraftInfoRec representing
  62.                                     current draft
  63.         <24>      5/4/95    eeh        1232095: factor out DeleteSelectedDraft
  64.         <23>      5/1/95    TÇ        1234420 StdTypIO functions should not
  65.                                     return default values
  66.         <22>     4/24/95    eeh        1228013: always draw vertical scroll bar
  67.         <21>     4/14/95    TÇ        #1235279 BB: InfoUtil & StdTypIO functions
  68.                                     should take Environment* and SU* when
  69.                                     possible
  70.         <20>     4/10/95    EL        1215536: creation date of draft should be
  71.                                     creation date of next draft property.
  72.                                     1236414: There is no temporary draft for
  73.                                     read only document.
  74.         <19>      4/7/95    EL        Use ODGetTime_TProp for document exchange.
  75.         <18>      4/7/95    eeh        1236464: TRY around document->AcquireDraft
  76.         <17>     3/24/95    eeh        1229961, 1215528: change callbacks to use
  77.                                     IText*
  78.         <16>     3/15/95    eeh        1193824: move drawing routines to
  79.                                     useritemproc
  80.         <15>      3/8/95    eeh        1180986: setwtitle -> SetWTitle
  81.         <14>      3/6/95    jpa        Use dialog utilities (ODGetNewDialog,
  82.                                     ODDialogFilterProc) to make dlogs movable.
  83.                                     [1218957] Also don't leave rsrc fork
  84.                                     active.
  85.         <13>     2/20/95    TÇ        #1210979 BB: 5-$ Bugs need to be evaluated
  86.                                     and removed from Shell
  87.         <12>     1/26/95    eeh        1214080: OpenDoc really uses kODMacIText,
  88.                                     not kODIntlText.
  89.         <11>     1/12/95    jpa        Don't use obsolete Toolbox names. [1211211]
  90.         <10>    12/20/94    VL        1195012: Make Storage calls be
  91.                                     marshallable.
  92.          <9>    12/19/94    eeh        1192626: remove "current" draft; fix button
  93.                                     hiliting; nuke horizontal scroll bar, etc.
  94.          <8>     9/26/94    TÇ        #1188566 Removing Drafts
  95.          <7>     9/23/94    VL        1155579, 1184272: Use StorUtil to
  96.                                     create/get container and its file.
  97.          <6>     8/29/94    TÇ        #1183567 StdTypIO routine implementation &
  98.                                     fixup
  99.          <5>     8/12/94    NP        1180762-Correct usage of GetUserName.
  100.                                     Correctly dipose of IText after using.
  101.          <4>     7/27/94    eeh        use ODSetITextProp and ODGetITextProp
  102.                                     (fixed Draft dialog garbage)
  103.          <3>     7/23/94    TÇ        #include "DraftWLD.h"
  104.          <2>     7/18/94    TÇ        changed include of PtFrInfo.h to StTypIO.h
  105.          <1>     6/27/94    TÇ        first checked in
  106.          <0>     6/27/94    SV        SOMverted
  107.         <10>     5/10/94    TÇ        #1162405 Removed explicit ASLM dependency
  108.                                     for using resources
  109.          <9>      5/9/94    MB        #1162181: Changes necessary to install MMM.
  110.          <8>      5/3/94    eeh        bug #1155857: incorporate LDEF; remove
  111.                                     hard-coded number limits
  112.          <7>      4/1/94    TÇ        #1154941: Get OpenDoc source to actually
  113.                                     compile for PowerPC
  114.          <6>     3/31/94    eeh        bug #1153999: use XMPG/SetITextProp,
  115.                                     different PStrToIntl.
  116.          <5>     3/28/94    CG        1153547: Use new method
  117.                                     ODSession::GetUserName instead of
  118.                                     calling system directly.
  119.          <4>     3/24/94    eeh        bug #1153053: Changes for PPC nativity (or
  120.                                     is it nativeness...?)
  121.          <3>     3/18/94    CC        Value type of user property changed from
  122.                                     kXMPAppleTEXT to kODASCIIText (but should
  123.                                     be international text!).  (1151636)
  124.          <2>      3/1/94    JA        Made local fns static.
  125.         <12>      2/7/94    JA        Utilities.h --> XMPUtils.h
  126.         <11>      2/7/94    TÇ        more fixes to compile with PPC Headers
  127.         <10>      2/4/94    TÇ        fixes to compile with PPC Universal headers
  128.          <9>     1/28/94    TÇ        bug fixes & implemented double click = open
  129.          <8>     1/25/94    NP        TÇ: implemented
  130.          <7>     1/20/94    TÇ        got rid of warnings
  131.          <6>     1/14/94    TÇ        added skeleton code from HI to show dialogs
  132.          <5>     1/13/94    TÇ        reworked and added some code for latest
  133.                                     round of HI changes
  134.          <3>     8/24/93    TÇ        removed code made obsolete by HI Changes
  135.          <2>     8/19/93    TÇ        fixed some stuff
  136.          <1>     7/14/93    TÇ        first checked in
  137.  
  138.     To Do:
  139.     In Progress:
  140.         
  141. */
  142.  
  143.  
  144. #ifndef _DRAFTWLD_
  145. #include "DraftWLD.h"
  146. #endif
  147.  
  148. #ifndef SOM_Module_OpenDoc_StdProps_defined
  149. #include <StdProps.xh>
  150. #endif
  151.  
  152. #ifndef _DRAFTWN_
  153. #include "DraftWn.h"
  154. #endif
  155.  
  156. #ifndef _TEMPOBJ_
  157. #include "TempObj.h"
  158. #endif
  159.  
  160. #ifndef _USERSRCM_
  161. #include <UseRsrcM.h>
  162. #endif
  163.  
  164. #ifndef SOM_ODDocument_xh
  165. #include <Document.xh>
  166. #endif
  167.  
  168. #ifndef SOM_ODContainer_xh
  169. #include <ODCtr.xh>
  170. #endif
  171.  
  172. #ifndef _ODUTILS_
  173. #include <ODUtils.h>
  174. #endif
  175.  
  176. #ifndef SOM_ODWindowState_xh
  177. #include <WinStat.xh>
  178. #endif
  179.  
  180. #ifndef SOM_ODWindowIterator_xh
  181. #include <WinIter.xh>
  182. #endif
  183.  
  184. #ifndef SOM_ODWindow_xh
  185. #include <Window.xh>
  186. #endif
  187.  
  188. #ifndef _DOCUTILS_
  189. #include <DocUtils.h>
  190. #endif
  191.  
  192. #ifndef SOM_ODStorageUnit_xh
  193. #include <StorageU.xh>
  194. #endif
  195.  
  196. #ifndef SOM_ODClipboard_xh
  197. #include <Clipbd.xh>
  198. #endif
  199.  
  200. #ifndef SOM_ODStorageUnitView_xh
  201. #include <SUView.xh>
  202. #endif
  203.  
  204. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  205. #include <StdTypes.xh>
  206. #endif
  207.  
  208. #ifndef _ODMEMORY_
  209. #include <ODMemory.h>
  210. #endif
  211.  
  212. #ifndef _PLFMFILE_
  213. #include <PlfmFile.h>
  214. #endif
  215.  
  216. #ifndef _DLOGUTIL_
  217. #include <DlogUtil.h>
  218. #endif
  219.  
  220. #ifndef _STORUTIL_
  221. #include <StorUtil.h>
  222. #endif
  223.  
  224. #ifndef __TIME_H__
  225. #include <Time.h>
  226. #endif
  227.  
  228. #ifndef _PASCLSTR_
  229. #include <PasclStr.h>
  230. #endif
  231.  
  232. #ifndef _ISOSTR_
  233. #include <ISOStr.h>
  234. #endif
  235.  
  236. #ifndef _ITEXT_
  237. #include <IText.h>
  238. #endif
  239.  
  240. #ifndef __SCRIPT__
  241. #include <script.h>
  242. #endif
  243.  
  244. #ifndef __DIALOGS__
  245. #include <Dialogs.h>
  246. #endif
  247.  
  248. #ifndef __LISTS__
  249. #include <Lists.h>
  250. #endif
  251.  
  252. #ifndef __TOOLUTILS__
  253. #include <ToolUtils.h>
  254. #endif
  255.  
  256. #ifndef __RESOURCES__
  257. #include <Resources.h>
  258. #endif
  259.  
  260. #ifdef __SC__
  261. #ifndef __PACKAGES__
  262. #include <Packages.h>
  263. #endif
  264. #else
  265. #ifndef __TEXTUTILS__
  266. #include <TextUtils.h>
  267. #endif
  268. #endif
  269.  
  270. #ifndef __ICONS__
  271. #include <Icons.h>
  272. #endif
  273.  
  274. #ifndef _ODMEMORY_
  275. #include <ODMemory.h>
  276. #endif
  277.  
  278. #ifndef SOM_ODSession_xh
  279. #include <ODSessn.xh>
  280. #endif
  281.  
  282. #ifndef _STDTYPIO_
  283. #include <StdTypIO.h>
  284. #endif
  285.  
  286. #ifndef _STORUTIL_
  287. #include <StorUtil.h>
  288. #endif
  289.  
  290. #pragma segment DraftWindow
  291.  
  292. //==============================================================================
  293. // Constants
  294. //==============================================================================
  295.  
  296. #define tenPt            10
  297. #define kNoExpandClick    -1
  298. #define kNoRowHilited    -1
  299.  
  300.  
  301. #define no_ictb_exists        false    /* try using an ictb resource instead of code */
  302.  
  303. #define kXMPNewLineChar    '\n'
  304.  
  305. #define    kDraftsActiveControl 0
  306.  
  307. // macros for passing info about default button behavior.  Currently involves
  308. // setting the low-order bit in the listhandle, which on the mac *should*
  309. // always be clear.  A cleaner implementation might be advised....
  310.  
  311. #define CREATEISSET(self)    (((DraftWindow*)(self))->CreateIsSet())
  312. #define GETLISTHANDLE(self)    (((DraftWindow*)(self))->GetListHandle())
  313. #define GETLISTRECT(self, rectPtr)                                            \
  314.         (((DraftWindow*)(self))->GetListRect((rectPtr)))
  315. #define SETREADYTOCLOSE(self)                                                \
  316.         (((DraftWindow*)(self))->SetReadyToClose(kODTrue))
  317. #define CLEARREADYTOCLOSE(self)                                                \
  318.         (((DraftWindow*)(self))->SetReadyToClose(kODFalse))
  319. #define READYTOCLOSESET(self)                                                \
  320.         (((DraftWindow*)(self))->ReadyToClose())
  321. #define kNumColumns 4
  322. #define    kCommentsColumnIndex 3
  323.  
  324. const short kControlActive = 0;
  325.  
  326. //==============================================================================
  327. // Scalar Types
  328. //==============================================================================
  329.  
  330. //==============================================================================
  331. // Local Classes
  332. //==============================================================================
  333.  
  334. //==============================================================================
  335. // Function Prototypes
  336. //==============================================================================
  337.  
  338. static void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  339.         ODSShort row, const Rect* listItemRect );
  340. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow );
  341. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum );
  342. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  343.         short parentRowNum );
  344. static void AddRows( ListHandle listH, short startIndex, short numToAdd );
  345. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from );
  346. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects );
  347. static pascal void DrawBlackBoxItem(DialogPtr dlog, short theItem);
  348. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  349.         short *itemHit);
  350. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog, EventRecord *event,
  351.         short *itemHit);
  352. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  353.         short *itemHit );
  354. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  355.         Boolean hasContent );
  356. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  357.         ListHandle listH );
  358.  
  359. //==============================================================================
  360. // DraftWindow
  361. //==============================================================================
  362.  
  363. //------------------------------------------------------------------------------
  364. // Creation
  365. //------------------------------------------------------------------------------
  366.  
  367. DraftWindow::DraftWindow()
  368. {
  369.     fDraft        = kODNULL;
  370.     fDocument    = kODNULL;
  371.     fDraftInfo    = kODNULL;
  372.     fSelectedDraft = kODNULL;
  373.     fSelectedDraftNumber = 0;
  374. //    fExpandClickRow = kNoExpandClick;
  375. //    fHilitedRow = kODNULL;        // clear in Drafts() instead.
  376. }
  377.  
  378. void DraftWindow::InitDraftWindow(Environment* ev, ODDraft* draft)
  379. {    
  380.     fDraft         = draft;
  381.     fDocument    = draft->GetDocument(ev);
  382.     fListH        = kODNULL;
  383.     fCreateSet    = kODFalse;
  384.     fReadyToClose = kODFalse;
  385. }
  386.  
  387. //------------------------------------------------------------------------------
  388. // Destruction
  389. //------------------------------------------------------------------------------
  390.  
  391. DraftWindow::~DraftWindow()
  392. {            
  393.     ODReleaseObject(somGetGlobalEnvironment(),fSelectedDraft);
  394.     // dispose of DraftInfoRecs and collection
  395.     ODDeleteObject(fDraftInfo);
  396. }
  397.  
  398.  
  399. //------------------------------------------------------------------------------
  400. // Dialog
  401. //------------------------------------------------------------------------------
  402.  
  403. ListHandle DraftWindow::MakeAList(DialogPtr dlg, ODSShort* numLines,
  404.         long refcon )
  405. {
  406.     Rect        itemRect, boundsRect;
  407.     Handle        itemH;
  408.     short        scratchKind;
  409.  
  410.     /* create a scrolling list */
  411.  
  412.     GetDialogItem(dlg, kDraftsListUserItem, &scratchKind, &itemH, &itemRect);
  413.     itemRect.top -= 1;                                        
  414.     itemRect.left -= 1;                                        
  415.     SetRect(&boundsRect, 0, 0, 1, 0);                            /* one column list, 0 row count for now */
  416.  
  417.     FontInfo    scriptAppFontInfo;
  418.     GetFontInfo(&scriptAppFontInfo);
  419.     ODSShort cellHeight = scriptAppFontInfo.ascent +
  420.             scriptAppFontInfo.descent + scriptAppFontInfo.leading;
  421.     *numLines = (itemRect.bottom - itemRect.top) / cellHeight;
  422.  
  423.     fListRect = itemRect;
  424.     fListRect.bottom -= 1;
  425.     itemRect.right -= 15;
  426.     
  427.     InsetRect(&itemRect, 1, 1);                                    /* leave room for the frame */
  428.  
  429.     /* use the Application Font for the list items (cell size) */
  430.     long scriptAppFontSize = GetScriptVariable(smSystemScript,smScriptAppFondSize);
  431.     TextFont(HiWord(scriptAppFontSize));
  432.     TextSize(LoWord(scriptAppFontSize));        /* make look larger; icons will force this to be right once they're added */
  433.  
  434.     (LoWord(scriptAppFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptAppFontSize));
  435.  
  436.     Point cellSize;
  437.     SetPt(&cellSize, 500, cellHeight);
  438.     
  439.     /* now get the real desired font size */
  440.     long scriptSmallFontSize = GetScriptVariable(smSystemScript,smScriptSmallFondSize);
  441.     (LoWord(scriptSmallFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  442.  
  443.     Handle myHandle;
  444.     ListHandle listH;
  445.     { CUsingLibraryResources r;
  446.         myHandle = Get1Resource('LDEF',kDraftWinLDEFID);
  447.         THROW_IF_NULL(myHandle);
  448.         ListDefUPP LDEFUPP = NewListDefProc(DRAFTWINDOWLDEF);
  449.         (*(ListDefUPP*)&((*myHandle)[kDraftWinLDEFAddrOffset])) = LDEFUPP;
  450.         /* This above code written from suggestion in NIM:PPC System Software 1-35,1-36 */
  451.         
  452.         listH = LNew(&itemRect, &boundsRect, cellSize, kDraftWinLDEFID, dlg,
  453.                                         kODFalse, kODFalse, kODFalse, kODTrue);
  454.     }
  455.  
  456.     if (listH != nil)    
  457.     {                                            /* list was created */
  458.         (*listH)->refCon = refcon ;
  459.         /* resize list rectangle to only display whole cells */
  460.         itemRect.bottom -= (((short) (itemRect.bottom - itemRect.top)) % cellSize.v);
  461.         LSize(itemRect.right - itemRect.left, itemRect.bottom - itemRect.top, listH);
  462.         itemRect.right += 15;                /* add room for scroll bar */    
  463.         SetDialogItem(dlg, kDraftsListUserItem, scratchKind, itemH, &itemRect);
  464.     
  465. //        (*listH)->selFlags = lNoNilHilite;
  466. //        (*listH)->selFlags = (lOnlyOne | lNoNilHilite);
  467.         
  468.         LSetDrawingMode(kODFalse, listH);
  469.  
  470.         LDelRow(0, 0, listH);            /* delete everything in the list */
  471.         AddRows( listH, 0, this->CountDrafts() );
  472.  
  473.         LAutoScroll(listH);
  474.         LUpdate(dlg->visRgn, listH);
  475.         (*listH)->lastClick = *(Cell*)0L;
  476.         if ( fDraftInfo )
  477.             this->SetHilite( fDraftInfo, 0 );
  478. //        LSetDrawingMode(kODTrue, listH);
  479.     }
  480.     return listH;
  481. }    // DraftWindow::MakeAList
  482.  
  483. #if ODDebug
  484. void DraftWindow::CheckConsistency()
  485. {
  486.     if ( !fDraftInfo )
  487.         return;
  488.  
  489.     DraftInfoRec* dir = fDraftInfo;
  490.     short fullEntryCount = 0;
  491.     short dummyEntryCount = 0;
  492.     FullDraftInfoRec* fdir = kODNULL;
  493.     WASSERT( dir->GetComment() );
  494.     ODBoolean somethingExpanded = kODFalse;
  495.     ODBoolean foundHilite = kODFalse;
  496.     while ( dir )
  497.     {
  498.         if ( dir->GetDIRType() == kDIRTypeFull )
  499.         {
  500.             ++fullEntryCount;
  501.             fdir = (FullDraftInfoRec*)dir;
  502.             if ( fdir->ShouldHilite() )
  503.             {
  504.                 WASSERT( !foundHilite );
  505.                 foundHilite = kODTrue;
  506.             }
  507.             if ( fdir->IsExpanded() )
  508.             {
  509.                 somethingExpanded = kODTrue;
  510.                 WASSERT( fdir->GetCachedComment() != kODNULL );
  511.                 WASSERT( fdir->GetComment() != kODNULL );
  512.                 WASSERT( fdir->Next() != kODNULL );
  513.                 WASSERT( fdir->Next()->GetDIRType() != kDIRTypeFull );
  514.             }
  515.             else
  516.             {
  517.                 WASSERT( fdir->GetCachedComment() == kODNULL );
  518.                 WASSERT( fdir->GetComment() != kODNULL );
  519.             }
  520.         }
  521.         else
  522.         {
  523.             ++dummyEntryCount;
  524.             DummyDraftInfoRec* ddir = (DummyDraftInfoRec*)dir;
  525.             WASSERT( ddir->GetCommentOwner() );
  526.             WASSERT( ddir->GetCommentOwner() == fdir );
  527.             WASSERT( ddir->ShouldHilite() == fdir->ShouldHilite() );
  528.         }
  529.         dir = dir->Next();
  530.     }
  531.     if ( !somethingExpanded )
  532.         WASSERT( fullEntryCount == (*fListH)->dataBounds.bottom);
  533.     else
  534.         WASSERT( fullEntryCount+dummyEntryCount == (*fListH)->dataBounds.bottom);
  535.     WASSERT( foundHilite );
  536.     WASSERT( fullEntryCount == this->CountDrafts() );
  537. }
  538. #endif
  539.  
  540. DraftWinAction    DraftWindow::Drafts(Environment* ev, ODDraft* draft,
  541.         DraftWinAction prevAction, ODBoolean hasWriteAccess )
  542. {
  543.     // show the dialog/create the window and modally respond
  544.     // to events until dismissed
  545.     
  546.     short          itemKind,itemHit;
  547.     Rect        scratchRect;
  548.     Handle        scratchHandle;
  549.     
  550.     // worst case app heap memory usage between here and when the
  551.     // delete confirmation draft is up is 6448 bytes.  So I'm
  552.     // padding to 10000 to be safe.
  553.     // <eeh> need to reconsider now that comments expand?
  554.  
  555.     if ( !ODHaveFreeSpace( 10000, 0, kODTrue) )
  556.         return kDraftWinLowMemAbort;
  557.  
  558.     if ( draft != kODNULL )
  559.         fDraft = draft;        
  560.  
  561.     /// read and construct DraftInfo
  562.     fHilitedRow = kODNULL;        // clear this each time reopen dialog
  563.     fDraftInfo = this->InternalizeHistory(ev);
  564.  
  565.     GrafPort*    savePort;
  566.     GetPort(&savePort);
  567.  
  568.     TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  569.     ODSession *session = draftProps->GetSession(ev);
  570.     DialogPtr dlg;
  571.     {CUsingLibraryResources r;
  572.         dlg = ODGetNewDialog(ev,kDraftsDlgID,session,kODFalse);
  573.     }
  574.     THROW_IF_NULL(dlg);
  575.     SetPort(dlg);
  576.  
  577.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  578.             fDraft->GetDocument(ev)->GetContainer(ev));
  579.     Str255 dWinName;
  580.     ODName* fileName = file->GetName();
  581.     ODSLong savedRefNum;
  582.     BeginUsingLibraryResources(savedRefNum);
  583.     // DMc: ensure that string is deleted:
  584.     TempODString tempString = (char*) GetITextString(fileName, (StringPtr)kODNULL);
  585.     ConstStr255Param csp = (ConstStr255Param) (char*) tempString;
  586.     ReplaceIntoString( kDraftsWnTitleResID,
  587.             csp, kODNULL,
  588.             dWinName);
  589.     EndUsingLibraryResources(savedRefNum);
  590.     DisposeIText(fileName);
  591.  
  592.     SetWTitle(dlg,(StringPtr)dWinName);
  593.     ODDeleteObject(file);
  594.  
  595.     DialogPeek dlgPeek;
  596. #if no_ictb_exists
  597.     /* use the script's small font for the static text */
  598.     scriptSmallFontSize = GetScript(smSystemScript,smScriptSmallFondSize);    
  599.     TextFont(HiWord(scriptSmallFontSize));
  600.     (LoWord(scriptSmallFontSize) < tenPt) ?
  601.             TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  602.     TextFace(bold);
  603.  
  604.     /* WARNING: remember to set the font, face and size for update events */
  605.     dlgPeek = (DialogPeek) dlg;
  606.     (**(dlgPeek->textH)).txFont = HiWord(scriptSmallFontSize);
  607.     if (((**(dlgPeek->textH)).txSize = LoWord(scriptSmallFontSize)) < tenPt)
  608.         (**(dlgPeek->textH)).txSize = tenPt;
  609. //    (**(dlgPeek->textH)).txFace = bold;
  610. #endif
  611.  
  612.     UserItemUPP drawBoxItemUPP; // dialogs.h
  613.     drawBoxItemUPP    = NewUserItemProc(DrawBlackBoxItem);
  614.     
  615.     /* A horizontal line needs to be drawn above the list rectangle */
  616.     GetDialogItem(dlg, kDraftsHorizRectUserItem, &itemKind,
  617.             &scratchHandle, &scratchRect);
  618.     SetDialogItem(dlg, kDraftsHorizRectUserItem, itemKind,
  619.             (Handle)drawBoxItemUPP, &scratchRect);
  620.  
  621.     /* A rectangle needs to be drawn around the list column titles */
  622.     GetDialogItem(dlg, kDraftsHeaderRectUserItem, &itemKind,
  623.             &scratchHandle, &scratchRect);
  624.     SetDialogItem(dlg, kDraftsHeaderRectUserItem, itemKind,
  625.             (Handle)drawBoxItemUPP, &scratchRect);
  626.  
  627.     if ( hasWriteAccess  )
  628.     {
  629.         GetDialogItem(dlg, kDraftsCreateUserItem, &itemKind,
  630.                 &scratchHandle, &scratchRect);
  631.         SetDialogItem(dlg, kDraftsCreateUserItem, itemKind,
  632.                 (Handle)drawBoxItemUPP, &scratchRect);
  633.     }
  634.     else        // set up to draw box around create button
  635.     {
  636.         GetDialogItem(dlg, kDraftsCreateBtn, &itemKind, &scratchHandle,
  637.                 &scratchRect);
  638.         HiliteControl( (ControlHandle)scratchHandle, 255 );    // disable create
  639.     }
  640.  
  641.     GetDialogItem(dlg, kDraftsDoneUserItem, &itemKind,
  642.             &scratchHandle, &scratchRect);
  643.     SetDialogItem(dlg, kDraftsDoneUserItem, itemKind,
  644.             (Handle)drawBoxItemUPP, &scratchRect);
  645.  
  646.     GetDialogItem(dlg, kDraftsListUserItem, &itemKind,
  647.             &scratchHandle, &scratchRect);
  648.     SetDialogItem(dlg, kDraftsListUserItem, itemKind,
  649.             (Handle)drawBoxItemUPP, &scratchRect);
  650.  
  651.     /* create a scrolling list of draft information */
  652.     DraftLDEFCallbackInfo hc ;
  653.     hc.dialog = dlg;
  654.     hc.dir = fDraftInfo ;
  655.     hc.stringsProc = DrawDWUserStrings ;
  656.     
  657.  
  658.     GetDialogItem(dlg, kDraftsCreatorStaticTxt, &itemKind, &scratchHandle,
  659.             &scratchRect);
  660.     hc.rectEnds[0].right = scratchRect.right;
  661.     hc.rectEnds[0].left = scratchRect.left;
  662.     GetDialogItem(dlg, kDraftsDraftStaticTxt, &itemKind, &scratchHandle,
  663.             &scratchRect);
  664.     hc.rectEnds[1].right = scratchRect.right;
  665.     hc.rectEnds[1].left = scratchRect.left;
  666.     GetDialogItem(dlg, kDraftsCreatedStaticTxt, &itemKind, &scratchHandle,
  667.             &scratchRect);
  668.     hc.rectEnds[2].right = scratchRect.right;
  669.     hc.rectEnds[2].left = scratchRect.left;
  670.     GetDialogItem(dlg, kDraftsCommentStaticTxt, &itemKind, &scratchHandle,
  671.             &scratchRect);
  672.     hc.rectEnds[3].right = scratchRect.right;
  673.     hc.rectEnds[3].left = scratchRect.left;
  674.     
  675.     GetDialogItem(dlg, kDraftsArrowStaticTxt, &itemKind, &scratchHandle,
  676.             &scratchRect);
  677.     hc.arrowEnds.right = scratchRect.right;
  678.     hc.arrowEnds.left = scratchRect.left;
  679.  
  680.     fCreateSet = (prevAction == kDraftWinNone) && hasWriteAccess;
  681.  
  682.     session->GetClipboard(ev)->SetPlatformClipboard( ev, kODNULL );
  683.  
  684.     ODSShort numLines;
  685.     ListHandle listH = fListH = this->MakeAList(dlg, &numLines, (long)&hc );
  686.     ((WindowPeek)dlg)->refCon = (long)this;
  687.     dlgPeek = (DialogPeek) dlg;
  688.     UpdateDialog( dlg,(dlgPeek->window).port.visRgn);
  689.     ShowWindow(dlg);    
  690.  
  691.     // <eeh> does this work?
  692.     LSetDrawingMode(kODTrue, listH);
  693.     
  694.     DraftWinAction dWinAction = kDraftWinNone;
  695.     ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  696.     ModalFilterUPP modalFilter = NewModalFilterProc(CheckDeleteKeyFilterProc);
  697.     SetButtonStates( dlg, hasWriteAccess, fDraftInfo != kODNULL );
  698.     while (dWinAction == kDraftWinNone)
  699.     {
  700. #if ODDebug
  701.         this->CheckConsistency();
  702. #endif
  703.         ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  704.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  705.         ModalDialog( modalFilter, &itemHit );
  706.         EndUsingLibraryResources(savedRefNum);
  707.         
  708.         switch    (itemHit)
  709.         {
  710.             case kODUpArrowItem:
  711.             case kODPageUpArrowItem:
  712.             case kODHomeArrowItem:
  713.             case kODDownArrowItem:
  714.             case kODPageDownArrowItem:
  715.             case kODEndArrowItem:
  716. //                ArrowKeyScrollList( itemHit, listH, numLines,
  717. //                        this->CountDrafts()-1 );
  718.                 break;
  719.  
  720.             case kDraftsDoneBtn:
  721.                 dWinAction = kDraftWinDone;
  722.                 break;
  723.  
  724.             case kDraftsCreateBtn:
  725.                 LActivate(kODFalse,listH);
  726.                 if (this->CreateDraft(ev))
  727.                     dWinAction = kDraftWinCreate;
  728.                 LActivate(kODTrue,listH);
  729.                 ShowWindow(dlg);
  730.                 break;
  731.  
  732.             case kDraftsListUserItem:
  733.                 continue;
  734.  
  735.             case kDraftsDeleteBtn:
  736.             case kDraftsOpenBtn:
  737.                 WASSERT( fDraftInfo );
  738.                 FullDraftInfoRec* selDraftInfoRec =
  739.                         FirstSelectedRow( fDraftInfo );
  740.  
  741.                 WASSERT(selDraftInfoRec);
  742.                 ODReleaseObject(ev,fSelectedDraft);
  743.                 WASSERT(selDraftInfoRec->GetDIRType() == kDIRTypeFull);
  744.                 fSelectedDraft = selDraftInfoRec->Draft();
  745.                 fSelectedDraft->Acquire(ev);
  746.                 fSelectedDraftNumber = selDraftInfoRec->Number();
  747.  
  748.                 if    (itemHit == kDraftsDeleteBtn)
  749.                 {
  750.                     LActivate(kODFalse,listH);
  751.                     if (this->RemoveSelectedDrafts(ev))
  752.                         dWinAction = kDraftWinDelete;
  753.                     LActivate(kODTrue,listH);
  754.                     ShowWindow(dlg);
  755.                 }
  756.                 else 
  757.                 {
  758.                     dWinAction = kDraftWinOpen;
  759.                 }
  760.                 break;
  761.             default:
  762.                 break;
  763.         }
  764.         UpdateDialog(dlg,(dlgPeek->window).port.visRgn);
  765.     }
  766.  
  767.     if (listH != kODNULL)
  768.     {
  769.         CUsingLibraryResources r;
  770.         // Release LDEF and the UPP it points to after deleting the list:
  771.         Handle ldef = (**listH).listDefProc;
  772.         LDispose(listH);
  773.         DisposeRoutineDescriptor(
  774.                 (*(ListDefUPP*)&((*ldef)[kDraftWinLDEFAddrOffset])) );
  775.         ReleaseResource(ldef);
  776.     }
  777.  
  778.     DisposeRoutineDescriptor(modalFilter);
  779.     DisposeRoutineDescriptor(drawBoxItemUPP);
  780.     
  781.     DisposeDialog(dlg);
  782.     SetPort(savePort);
  783.     
  784.     // dispose of DraftInfoRecs and collection
  785.     ODDeleteObject(fDraftInfo);
  786.  
  787.     if (dWinAction == kDraftWinCreate)
  788.     {
  789.         ODReleaseObject(ev,fSelectedDraft);
  790.         fSelectedDraftNumber = 0;
  791.     }
  792.  
  793.     return dWinAction;
  794. }    // DraftWindow::Drafts
  795.  
  796. void    DraftWindow::DeleteSelectedDraft(Environment* ev, ODSession* session) 
  797. {
  798.     WASSERT(fSelectedDraft);
  799.     if (fSelectedDraft == fDraft) 
  800.         ; // can't delete current draft, this shouldn't happen!
  801.     else if (fSelectedDraft->GetRefCount(ev)>1)
  802.     {
  803.         // When the exceptionalert code becomes a utility, call it
  804.         // here.  That allow us to not THROW an error, which we don't
  805.         // want to do because there's no code to catch it in places
  806.         // where cleanup must be done.
  807.  
  808.         WARN( "kODErrOutstandingDraft: trying to delete open draft." );
  809.         SysBeep( 2 );
  810.     }
  811.     else 
  812.     {
  813.         ODDraft* fromDraft = 
  814.                 fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,    /* -- TÇ: $$$$$ Don't know if this is a true leak */
  815.                 fSelectedDraft, kODPosFirstAbove,kODFalse);
  816.         ODBoolean openDraftAbove = kODFalse;
  817.         // if draft just above selected draft is open, close and open it again
  818.         // otherwise the window would be pointing to the wrong draft
  819.         ODWindowState* windowState = session->GetWindowState(ev);
  820.         if (windowState->GetRootWindowCount(ev, fromDraft)) {
  821.             ODCloseDraft(ev, session, fromDraft);
  822.             openDraftAbove = kODTrue;
  823.         }
  824.         fDocument->SaveToAPrevDraft(ev,fromDraft,fSelectedDraft);
  825.         fDocument->CollapseDrafts(ev,fromDraft,fSelectedDraft); // Releases fSelectedDraft
  826.  
  827.         // open the selected draft again, this is now what was the draft just above it
  828.         if (openDraftAbove != kODFalse)
  829.             ODOpenDraft(ev, session, fSelectedDraft);
  830.         
  831.         // rename any open window in the drafts above
  832.         TempODDraft topDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,kODNULL,kODPosTop,kODFalse);
  833.         TempODDraft nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,
  834.                         fSelectedDraft, kODPosFirstAbove,kODFalse);
  835.         while (ODObjectsAreEqual(ev, nextDraft, topDraft) == kODFalse) {
  836.             windowState->SetDefaultWindowTitles(ev, nextDraft);
  837.             nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL, nextDraft, kODPosFirstAbove,kODTrue);
  838.         }
  839.  
  840.         fSelectedDraft = kODNULL;
  841.         fSelectedDraftNumber = 0;
  842.     }
  843. }
  844.  
  845. //------------------------------------------------------------------------------
  846. // InternalizeHistory
  847. //------------------------------------------------------------------------------
  848.  
  849. FullDraftInfoRec* DraftWindow::InternalizeHistory(Environment* ev)
  850. {
  851.     ODDocument*        document = fDraft->GetDocument(ev);
  852.     TempODDraft        prevDraft = kODNULL;
  853.     TempODDraft        bottomDraft = document->AcquireBaseDraft(ev,kODDPReadOnly);
  854.     FullDraftInfoRec*    aDraftInfoRec;
  855.     
  856.     if (HAS_WRITE_ACCESS(fDraft->GetPermissions(ev)))
  857.     {
  858.         WASSERT(document->Exists(ev, 0, fDraft, kODPosFirstBelow));
  859.  
  860.         prevDraft =    document->AcquireDraft(ev,kODDPReadOnly,kODNULL,fDraft,
  861.                     kODPosFirstBelow,kODFalse);
  862.     }
  863.     else 
  864.     {
  865.         prevDraft = fDraft;
  866.         prevDraft->Acquire(ev);
  867.     }
  868.  
  869.     FullDraftInfoRec* firstInfoRec = kODNULL;
  870.     if ( prevDraft != bottomDraft )
  871.     {
  872.         ODULong    curDraftNumber = 1;
  873.         for ( ; ; )
  874.         {
  875.             // $$$$$ <eeh> each draft gets aquired twice: here and in InitDraftInfoRec
  876.             prevDraft = document->AcquireDraft( ev, kODDPReadOnly, kODNULL,
  877.                     prevDraft, kODPosFirstBelow, kODTrue );
  878.     
  879.             FullDraftInfoRec* newDIR = new FullDraftInfoRec;
  880.             newDIR->InitDraftInfoRec(ev, prevDraft);
  881.     
  882.             if ( firstInfoRec )
  883.             {
  884.                 aDraftInfoRec->SetNext(newDIR);
  885.                 aDraftInfoRec = newDIR;
  886.             }
  887.             else
  888.             {
  889.                 aDraftInfoRec = newDIR;
  890.                 firstInfoRec = aDraftInfoRec;
  891.             }
  892.             if ( prevDraft == bottomDraft )
  893.                 break;
  894.             ++curDraftNumber;
  895.         }
  896.     
  897.         ODScriptCode script = FontToScript( GetSysFont() );
  898.         ODLangCode lang = GetScriptVariable( script, smScriptLang );
  899.     
  900.         for (aDraftInfoRec = firstInfoRec; aDraftInfoRec!=kODNULL;
  901.                 aDraftInfoRec =
  902.                 (FullDraftInfoRec*)((DraftInfoRec*)aDraftInfoRec)->Next())
  903.         {
  904.             aDraftInfoRec->SetNumber( curDraftNumber-- );
  905.             Str255 numberStr;
  906.             NumToString( aDraftInfoRec->Number(), numberStr);
  907.             aDraftInfoRec->SetNumberString( CreateIText( script, lang, numberStr ));
  908.         }
  909.     }
  910.  
  911.     return firstInfoRec;
  912. }
  913.  
  914. void    DraftWindow::DraftSaved(Environment* ev, ODDraft* draft) 
  915. {
  916.     ODTime    savedTimeDate;
  917.     time((time_t *)(&savedTimeDate));
  918.     TempODStorageUnit    su = draft->AcquireDraftProperties(ev);
  919.     ODSetTime_TProp(ev, su, kODPropDraftSavedDate, kODTime_T, savedTimeDate);
  920. }
  921.  
  922. ODSShort    DraftWindow::CountDrafts()
  923. {
  924.     DraftInfoRec* dir = fDraftInfo;
  925.     ODSShort result;
  926.     for ( result = 0; dir; dir = dir->Next() )
  927.         if ( dir->GetDIRType() == kDIRTypeFull )
  928.             ++result;
  929.     return result;
  930. }
  931.  
  932. ODBoolean    DraftWindow::CreateDraft(Environment* ev)
  933. {
  934.     short          itemHit,itemKind;
  935.     Handle        itemHandle;
  936.     Rect        scratchRect;
  937.     DialogPtr      dlg;
  938.     Str255        aS255;
  939.     ODBoolean    result;
  940.     GrafPort*    savePort;
  941.  
  942.     TempODStorageUnit su = fDraft->AcquireDraftProperties(ev);
  943.     ODSession *session = su->GetSession(ev);
  944.  
  945.     GetPort(&savePort);
  946.     { CUsingLibraryResources r;
  947.         dlg  = ODGetNewDialog(ev,kCreateDraftsDlgID,session);
  948.     }
  949.     THROW_IF_NULL(dlg);
  950.     SetPort(dlg);
  951.  
  952.     SetDialogDefaultItem(dlg, kCreateDraftsCreateBtn);
  953.     SetDialogCancelItem(dlg, kCreateDraftsCancelBtn);
  954.  
  955.     GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemKind,
  956.             &itemHandle, &scratchRect);
  957.     ODIText userName;
  958.     session->GetUserName(ev, &userName);
  959.     Str255 userNamePStr ;
  960.     IntlToPStr(&userName, userNamePStr);
  961.     SetDialogItemText(itemHandle,userNamePStr);
  962.     DisposeITextStruct(userName);
  963.     
  964.     /* make the Comments edit text field active: (0, 0) = beginning of text */
  965.     SelectDialogItemText(dlg, kCreateDraftsCommentsEditTxt, 0, 0);
  966.     
  967.     /* get the draft # dynamically and add to static text… */
  968.     ODULong num = fDraftInfo?fDraftInfo->Number() + 1 : 1;
  969.     NumToString( num, aS255 );
  970.  
  971.     // This acts to replace the "^0" in static text item 8 with the
  972.     // number of the draft.  Since item 8 is the only static text item
  973.     // in the dialog we don't have to say which one.  I guess....
  974.     ParamText(aS255,"\p","\p","\p");
  975.  
  976.     DialogScriptData dsd;
  977.     ODUseDialogScriptData( &dsd, dlg );
  978.  
  979.     ShowWindow(dlg);
  980.     
  981.     ModalFilterUPP modalFilter =
  982.             NewModalFilterProc(CheckKeyScriptFirstFilterProc);
  983.  
  984.     ODUseCommandKeyStringsResource( kDraftsCreateCmdKeyStrs );
  985.     do {
  986.         ODSLong savedRefNum;
  987.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  988.         ModalDialog( modalFilter, &itemHit );
  989.  
  990.         EndUsingLibraryResources(savedRefNum);
  991.         switch(itemHit)
  992.         {
  993.             case kCreateDraftsNameEditTxt:
  994.                 break;
  995.             case kCreateDraftsCommentsEditTxt:
  996.                 break;
  997.         }
  998.     } while ((itemHit != kCreateDraftsCreateBtn) &&
  999.             (itemHit != kCreateDraftsCancelBtn));
  1000.  
  1001.     DisposeRoutineDescriptor(modalFilter);
  1002.  
  1003.     result = (itemHit == kCreateDraftsCreateBtn);
  1004.     if (result)
  1005.     {
  1006.         Str255 aStr255;
  1007.         
  1008.     // update Name
  1009.         GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemHit,
  1010.                 &itemHandle, &scratchRect);
  1011.         GetDialogItemText(itemHandle,aStr255);
  1012.         TempODIText name = CreateIText( dsd.Script(), dsd.Language(),
  1013.                 (StringPtr)aStr255 );
  1014.         ODSetITextProp( ev, su, kODPropModUser, kODMacIText, name);
  1015.  
  1016.     // update Comments.  Note that it's now possible to display long ones
  1017.     // and that therefore we want to allow them bigger than 255.
  1018.         GetDialogItem(dlg, kCreateDraftsCommentsEditTxt, &itemHit, &itemHandle,
  1019.                 &scratchRect);
  1020.         ODSize strLen = GetHandleSize(itemHandle);
  1021.         TempODIText comments = CreateIText( dsd.Script(), dsd.Language(),
  1022.                 (ODUByte*)*itemHandle, strLen );
  1023.         ODSetITextProp( ev, su, kODPropDraftComment, kODMacIText, comments);
  1024.     }
  1025.     DisposeDialog(dlg);
  1026.     SetPort(savePort);
  1027.     return result;
  1028. }    // CreateDraft()
  1029.  
  1030.  
  1031. ODBoolean    DraftWindow::RemoveSelectedDrafts(Environment* ev)
  1032. {
  1033.     short          itemHit;
  1034.     DialogPtr      dlg;
  1035.     Str255        aS255,aS2552;
  1036.     GrafPort*    savePort;
  1037.  
  1038.     GetPort(&savePort);
  1039.     {    
  1040.         TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  1041.         ODSession *session = draftProps->GetSession(ev);
  1042.         CUsingLibraryResources r;
  1043.         dlg = ODGetNewDialog( ev, kDeleteDraftsDlogID, session );
  1044.     }
  1045.     THROW_IF_NULL(dlg);
  1046.     SetPort(dlg);
  1047.  
  1048.     SetDialogDefaultItem(dlg, kDeleteDraftsCancelBtn);
  1049.     SetDialogCancelItem(dlg, kDeleteDraftsCancelBtn);
  1050.  
  1051.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  1052.             fDraft->GetDocument(ev)->GetContainer(ev));
  1053.  
  1054.     file->GetAsciiName((char*)aS255,255);
  1055.     ODDeleteObject(file);
  1056.     CToPascalString((char*)aS255);
  1057.     NumToString( fSelectedDraftNumber, aS2552 );
  1058.     ParamText(aS2552,aS255,"\p","\p");
  1059.  
  1060.     ShowWindow(dlg);
  1061.     ModalFilterUPP modalFilter = NewModalFilterProc( CheckDeleteKeyFilterProc );
  1062.     
  1063.     do {
  1064.         ODSLong savedRefNum;
  1065.         BeginUsingLibraryResources(savedRefNum);    // for the cmd key str#
  1066.         ModalDialog( modalFilter, &itemHit );
  1067.         EndUsingLibraryResources(savedRefNum);
  1068.     } while ((itemHit != kDeleteDraftsCancelBtn) &&
  1069.             (itemHit != kDeleteDraftsDeleteBtn));
  1070.     
  1071.     DisposeRoutineDescriptor(modalFilter);
  1072.     DisposeDialog(dlg);
  1073.     SetPort(savePort);
  1074.  
  1075.     return itemHit == kDeleteDraftsDeleteBtn;
  1076. }
  1077.  
  1078. void DraftWindow::SetHilite( DraftInfoRec* from, short whichRow )
  1079. {
  1080.     if ( fHilitedRow != kODNULL )
  1081.         SetRows( fHilitedRow, 0, kODFalse, fListH );
  1082.     SetRows( from, whichRow, kODTrue, fListH );
  1083.     fHilitedRow = (FullDraftInfoRec*)GetNthRow( from, whichRow );
  1084. }
  1085.  
  1086. void    DraftWindow::Print()
  1087. {
  1088. }
  1089.  
  1090. //==============================================================================
  1091. // DraftInfoRec
  1092. //==============================================================================
  1093.  
  1094. DraftInfoRec::DraftInfoRec()
  1095. {
  1096.     fDIRType            = kDIRTypeUnknown;
  1097. //    fFirst                = kODNULL;
  1098.     fNext                 = kODNULL;
  1099.     fComment            = kODNULL;
  1100. }
  1101.  
  1102. //==============================================================================
  1103. // DummyDraftInfoRec
  1104. //==============================================================================
  1105.  
  1106. DummyDraftInfoRec::DummyDraftInfoRec()
  1107. {
  1108.     this->SetDIRType( kDIRTypeDummy );
  1109.     this->SetShouldHilite( kODFalse );
  1110.  
  1111. //    fPartialComment = kODNULL;
  1112.     fCommentOwner    = kODNULL;
  1113. }
  1114.  
  1115. //==============================================================================
  1116. // FullDraftInfoRec
  1117. //==============================================================================
  1118.  
  1119. //------------------------------------------------------------------------------
  1120. // Creation
  1121. //------------------------------------------------------------------------------
  1122.  
  1123. FullDraftInfoRec::FullDraftInfoRec()
  1124. {
  1125.     this->SetDIRType( kDIRTypeFull );
  1126.     this->SetShouldHilite( kODFalse );
  1127.  
  1128.     fDraft                 = kODNULL;
  1129.     fDraftProperties    = kODNULL;
  1130.     fDraftID             = kODNULL;
  1131.     fDraftNumber         = 0;
  1132.     fDraftNumberString    = kODNULL;
  1133.     fSaved                = kODNULL;
  1134.     fSavedString        = kODNULL;
  1135.     fCachedComment        = kODNULL;
  1136.     fModifiedBy            = kODNULL;
  1137.     fCanExpand            = kODFalse;
  1138. }
  1139.  
  1140. void FullDraftInfoRec::InitDraftInfoRec(Environment* ev, ODDraft* draft )
  1141. {    
  1142.     draft->Acquire(ev);
  1143.     fDraft = draft;
  1144.     fDraftProperties = draft->AcquireDraftProperties(ev);
  1145.     fDraftID = draft->GetID(ev);
  1146.  
  1147.     fModifiedBy = ODGetITextProp( ev, fDraftProperties,
  1148.                         kODPropModUser, kODMacIText, kODNULL);
  1149.  
  1150.     fSaved = ODGetTime_TProp(ev, fDraftProperties, kODPropDraftSavedDate,
  1151.             kODTime_T);
  1152.  
  1153.     Str255 dateString;
  1154.     IUDateString( fSaved, shortDate, dateString );
  1155.     Str255 timeString;
  1156.     IUTimeString( fSaved, kODFalse, timeString );
  1157.     
  1158.     Str255 dateTimeString;
  1159.     ODSLong savedRefNum;
  1160.     BeginUsingLibraryResources(savedRefNum);
  1161.     ReplaceIntoString( kDraftsWnDateSpaceResID, dateString,
  1162.             timeString, dateTimeString );
  1163.     EndUsingLibraryResources(savedRefNum);
  1164.     ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1165.     ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1166.     fSavedString = CreateIText( script, lang, dateTimeString );
  1167.  
  1168.     ODIText* comment = ODGetITextProp( ev, fDraftProperties,
  1169.                         kODPropDraftComment, kODMacIText, kODNULL );
  1170.     WASSERT( comment );
  1171.     this->SetComment( comment );
  1172. }
  1173.  
  1174.  
  1175. //------------------------------------------------------------------------------
  1176. // Destruction
  1177. //------------------------------------------------------------------------------
  1178.  
  1179. DraftInfoRec::~DraftInfoRec()
  1180. {
  1181.     ODDeleteObject(fNext);
  1182.     DisposeIText(fComment);
  1183. }
  1184.  
  1185. #if ODDebug
  1186. DummyDraftInfoRec::~DummyDraftInfoRec()
  1187. {
  1188.     WASSERT( this->GetDIRType() == kDIRTypeDummy);
  1189. }
  1190. #endif
  1191.  
  1192. FullDraftInfoRec::~FullDraftInfoRec()
  1193. {
  1194.     WASSERT( this->GetDIRType() == kDIRTypeFull);
  1195.     Environment* ev = somGetGlobalEnvironment();
  1196.     
  1197.     ODReleaseObject(ev,fDraftProperties);
  1198.     ODReleaseObject(ev,fDraft);
  1199.     
  1200.     DisposeIText(fDraftNumberString);
  1201.     DisposeIText(fSavedString);
  1202.     DisposeIText(fModifiedBy);
  1203.     DisposeIText(fCachedComment);
  1204. }
  1205.  
  1206. //------------------------------------------------------------------------------
  1207. // filter procs
  1208. //------------------------------------------------------------------------------
  1209.  
  1210. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  1211.         short *itemHit )
  1212. {    
  1213.     Rect        itemRect;
  1214.     short        itemType;
  1215.     Handle        itemHandle;
  1216.     long refcon = ((WindowPeek)dialog)->refCon;
  1217.     DraftWindow* self = (DraftWindow*)refcon;
  1218.     ListHandle listH = self->GetListHandle();
  1219.     ODBoolean result = kODFalse;
  1220.  
  1221.     if (event->what == mouseUp)
  1222.     {
  1223.         if ( READYTOCLOSESET( refcon ) )
  1224.         {
  1225.             *itemHit = kDraftsOpenBtn;
  1226.             result = kODTrue;
  1227.         }
  1228.     }
  1229.     else if (event->what == mouseDown)
  1230.     {
  1231.         GetDialogItem(dialog, kDraftsListUserItem, &itemType, &itemHandle, &itemRect);
  1232.         Point mpt = event->where;
  1233.         SetPort(dialog);
  1234.         GlobalToLocal(&mpt);
  1235.         if ( PtInRect(mpt, &itemRect) )
  1236.         {
  1237.             if ( LClick( mpt, event->modifiers, listH ) )
  1238.             {
  1239.                 WASSERT( !READYTOCLOSESET( refcon ) );
  1240.                 SETREADYTOCLOSE( refcon );
  1241.             }
  1242.             else if ( self->ProcessMousedownInList( dialog, listH, mpt ) )
  1243.                 InvalRect( &itemRect );
  1244.             *itemHit = kDraftsListUserItem;
  1245.             result = kODTrue;
  1246.         }
  1247.     }
  1248.     // <eeh> autoKey too?
  1249.     else if ( (event->what == keyDown) && !CREATEISSET(refcon) )
  1250.     {
  1251.         // the "done" button is shown as the default though it is item
  1252.         // #2, so we need to override the ODArrowKeyFilterProc's behavior.
  1253.         char key = event->message & charCodeMask;
  1254.         if ( (key == kEnterKey) || (key ==kReturnKey) )
  1255.         {
  1256.             FlashButtonItem( dialog, kDraftsDoneBtn );
  1257.             *itemHit = kDraftsDoneBtn;
  1258.             result = kODTrue;
  1259.         }
  1260.     }
  1261.  
  1262.     return result || ODArrowKeyFilterProc( dialog, event, itemHit );
  1263. }
  1264.  
  1265. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog,
  1266.         EventRecord *event, short *itemHit)
  1267. {
  1268.     // pass to the next filter proc.  This one just changes state, never
  1269.     // consuming the event.
  1270.     return CheckKeyScriptChangeFilterProc( dialog, event, itemHit )
  1271.             || ODButtonKeyFilterProc( dialog, event, itemHit );
  1272. }
  1273.  
  1274. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow )
  1275. {
  1276.     WASSERT( from );
  1277.     WASSERT( whichRow >= 0 );
  1278.     while ( whichRow-- )
  1279.     {
  1280.         from = from->Next();
  1281.         WASSERT( from );
  1282.     }
  1283.     return from;
  1284. }
  1285.  
  1286. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  1287.         ListHandle listH )
  1288. {
  1289.     dir = GetNthRow( dir, startRow );
  1290.     WASSERT(dir);
  1291.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1292.     dir->SetShouldHilite( newValue );
  1293.     Cell cell;
  1294.     cell.h = 0;
  1295.     cell.v = startRow;
  1296.     while ( ((dir = dir->Next()) != NULL) && dir->GetDIRType() == kDIRTypeDummy )
  1297.     {
  1298.         dir->SetShouldHilite( newValue );
  1299.         ++cell.v;
  1300.     }
  1301. }
  1302.  
  1303. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from )
  1304. {
  1305.     while ( from && !from->ShouldHilite() )
  1306.         from = (FullDraftInfoRec*)from->Next();
  1307.  
  1308.     WASSERT( from );
  1309.     WASSERT( from->GetDIRType() == kDIRTypeFull );
  1310.     return (FullDraftInfoRec*)from;
  1311. }
  1312.  
  1313. static pascal void OutlineButton(Rect *theBox, DialogPtr dlog)
  1314. {    
  1315.     GrafPtr oldPort;
  1316.     GetPort( &oldPort );
  1317.     SetPort( dlog );
  1318.  
  1319.     PenState curPen;
  1320.     GetPenState( &curPen );
  1321.     PenNormal();
  1322.     PenSize( 3, 3 );
  1323.     FrameRoundRect( theBox, 16, 16 );
  1324.     
  1325.     SetPenState( &curPen );
  1326.     SetPort( oldPort );
  1327. }
  1328.  
  1329. static pascal void DrawBlackBoxItem(DialogPtr dlog, short theItem)
  1330. {
  1331.     Rect     boxRect;
  1332.     Handle    scratchHandle;
  1333.     short    scratchKind;
  1334.     
  1335.     GetDialogItem(dlog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1336.     switch ( theItem )
  1337.     {
  1338.         case kDraftsHorizRectUserItem:
  1339.         case kDraftsHeaderRectUserItem:
  1340.             DrawItemFrame(dlog,theItem);
  1341.             break;
  1342.         case kDraftsCreateUserItem:
  1343.         case kDraftsDoneUserItem:
  1344.             ODBoolean createIsDefault = CREATEISSET(((WindowPeek)dlog)->refCon);
  1345.             if ( createIsDefault && theItem == kDraftsCreateUserItem)
  1346.                 OutlineButton(&boxRect, dlog);
  1347.             else if ( !createIsDefault && theItem == kDraftsDoneUserItem)
  1348.                 OutlineButton(&boxRect, dlog);
  1349.             break;
  1350.         case kDraftsListUserItem:
  1351.             LUpdate(dlog->visRgn, GETLISTHANDLE(((WindowPeek)dlog)->refCon));
  1352.             Rect listRect;
  1353.             GETLISTRECT( ((WindowPeek)dlog)->refCon, &listRect );
  1354.             FrameRect( &listRect );
  1355.             break;
  1356.     }
  1357. }
  1358.  
  1359. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum )
  1360. {
  1361.     WASSERT( dir );
  1362.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1363.  
  1364.     DisposeIText( dir->GetComment() );
  1365.     dir->UncacheComment();
  1366.  
  1367.     // Patch around the dummy entries and dispose them.  Remember that
  1368.     // ~DraftInfoRec deletes fNext recursively, so clip the list free
  1369.     // at both ends before deleting.
  1370.  
  1371.     DummyDraftInfoRec* findNextFull = (DummyDraftInfoRec*)dir->Next();
  1372.     WASSERT(findNextFull);
  1373.     DummyDraftInfoRec* rememberPrev = kODNULL;
  1374.     short removedCount = 0;
  1375.     while ( findNextFull && (findNextFull->GetDIRType() != kDIRTypeFull) )
  1376.     {
  1377.         rememberPrev = findNextFull;
  1378.         findNextFull = (DummyDraftInfoRec*)findNextFull->Next();
  1379.         ++removedCount;
  1380.     }
  1381.     WASSERT( rememberPrev );
  1382.     rememberPrev->SetNext( kODNULL );
  1383.     delete dir->Next();        // this is the head of the list
  1384.  
  1385.     dir->SetNext( findNextFull );
  1386.     
  1387.     LDelRow( removedCount, parentRowNum, listH );
  1388. }
  1389.  
  1390. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects )
  1391. {
  1392.     TEHandle hTE = TENew( bothRects, bothRects );
  1393.  
  1394.     short newFont = GetScriptVariable( GetITextScriptCode(iText),
  1395.             smScriptAppFond );
  1396.     (*hTE)->txFont = newFont;
  1397.     TESetText( GetITextPtr( iText ), GetITextStringLength(iText), hTE );
  1398.     return hTE;
  1399. }
  1400.  
  1401. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  1402.         short parentRowNum )
  1403. {
  1404.     WASSERT(dir);
  1405.     WASSERT(dir->GetDIRType() == kDIRTypeFull);
  1406.     
  1407.     // Get the text of the comment, figure out how many lines it'll require
  1408.     // not truncated, and create dummy DraftInfoRecs each of them holding
  1409.     // one line.  TE will calculate line breaks based on a rect given,
  1410.     // so use the left and right fields from the comments column.
  1411.     // REMEMBER that the first line goes in the existing "parent" entry.
  1412.     
  1413.     Rect itemRect;
  1414.     short ignoreType;
  1415.     Handle ignoreHandle;
  1416.     GetDialogItem( dialog, kDraftsCommentStaticTxt, &ignoreType, &ignoreHandle,
  1417.             &itemRect );
  1418.     itemRect.top = 0;
  1419.     itemRect.bottom = 0x7fff;        // why be shy?
  1420.     itemRect.right -= 1;            // make TE linewrap same as our trunc function
  1421.     
  1422.     ODIText* iText = dir->GetComment();
  1423.     // save off the truncatable comment for when we're contracted
  1424.     dir->CacheComment();
  1425.     
  1426.     TEHandle teh = ITextToTERec( iText, &itemRect );
  1427.  
  1428.     HLock( (Handle)teh );
  1429.     HLock( (*teh)->hText );
  1430.     char* currentLine = *(*teh)->hText;
  1431.     short* curLineStart = (*teh)->lineStarts;
  1432.     WASSERT( *curLineStart == 0 );
  1433.     ODScriptCode script = GetITextScriptCode( iText );
  1434.     ODLangCode lang = GetITextLangCode( iText );
  1435.     
  1436.     FullDraftInfoRec* savedNext = (FullDraftInfoRec*)dir->Next();
  1437.     DraftInfoRec* currentParent = dir;
  1438.     ODBoolean hiliteState = dir->ShouldHilite();
  1439.     
  1440.     short numLines = (*teh)->nLines;
  1441.     LSetDrawingMode(kODFalse, listH);                                    /* turn list drawing off */
  1442.     AddRows( listH, parentRowNum, numLines-1 );
  1443.     LSetDrawingMode(kODTrue, listH);                                    /* turn list drawing off */
  1444.     for ( short i = 0 ;i < numLines; ++i )
  1445.     {
  1446.         ODUByte* thisLine = (ODUByte*)¤tLine[*curLineStart++];
  1447.         ODUByte* nextLine = (ODUByte*)¤tLine[*curLineStart];
  1448.         ODSize len = nextLine - thisLine;
  1449.         ODIText* partialComment = CreateIText( script, lang, thisLine, len );
  1450.  
  1451.         if ( i == 0 )
  1452.         {
  1453.             dir->SetComment( partialComment );
  1454.         }
  1455.         else
  1456.         {
  1457.             DummyDraftInfoRec* newDummy = new DummyDraftInfoRec;
  1458.             newDummy->SetComment( partialComment );
  1459.             newDummy->SetCommentOwner( dir );
  1460.             newDummy->SetShouldHilite( hiliteState );
  1461.             
  1462.             currentParent->SetNext(newDummy);
  1463.             currentParent = newDummy;
  1464.         }
  1465.     }
  1466.     
  1467.     TEDispose( teh );
  1468.     currentParent->SetNext(savedNext);
  1469. }
  1470.  
  1471. ODBoolean DraftWindow::ProcessMousedownInList( DialogPtr dialog,
  1472.         ListHandle listH, Point mpt )
  1473. {
  1474.     // get last cell clicked in, but
  1475.     // ignore it if the cell doesn't exist (why is this necessary?)
  1476.     Cell lastClick = LLastClick( listH );
  1477.     if ( (lastClick.v) == -1 ||
  1478.             (lastClick.v >= (*listH)->dataBounds.bottom) )
  1479.         return kODFalse;
  1480.  
  1481.     ODBoolean result = kODFalse;
  1482.  
  1483.     DraftInfoRec* dir = GetNthRow( fDraftInfo, lastClick.v );
  1484.     WASSERT( dir );
  1485.  
  1486.     if ( dir->GetDIRType() == kDIRTypeDummy )
  1487.     {
  1488.         DraftInfoRec* parent =
  1489.                 ((DummyDraftInfoRec*)dir)->GetCommentOwner();
  1490.         ODBoolean isHilited = dir->ShouldHilite();
  1491.         WASSERT( isHilited == parent->ShouldHilite() );
  1492.         if ( !isHilited )
  1493.         {
  1494.             this->SetHilite( parent, 0 );
  1495.             result = kODTrue;
  1496.         }
  1497.         return result;
  1498.     }
  1499.  
  1500.     Rect scratchRect;
  1501.     short itemType;
  1502.     Handle ignore;
  1503.     GetDialogItem(dialog, kDraftsArrowStaticTxt, &itemType,
  1504.             &ignore, &scratchRect);
  1505.     ODBoolean inGrowColumn = (mpt.h > scratchRect.left)
  1506.             && (mpt.h < scratchRect.right);
  1507.     
  1508.     if ( inGrowColumn && ((FullDraftInfoRec*)dir)->CanExpand() )
  1509.     {
  1510.         if ( ((FullDraftInfoRec*)dir)->IsExpanded() )
  1511.             ContractList( (FullDraftInfoRec*)dir, listH, lastClick.v );
  1512.         else
  1513.             ExpandList( (FullDraftInfoRec*)dir, listH, dialog, lastClick.v );
  1514.         result = kODTrue;
  1515.     }
  1516.     else if ( !dir->ShouldHilite() )
  1517.     {
  1518.         this->SetHilite( dir, 0 );
  1519.         result = kODTrue;
  1520.     }
  1521.     return result;
  1522. }
  1523.  
  1524.  
  1525. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  1526.         short *itemHit)
  1527. {
  1528.     ODBoolean result = kODFalse;
  1529.     ODBoolean isDraftsDlog = ((WindowPeek)dialog)->refCon != 0;
  1530.  
  1531.     if (event->what == keyDown)
  1532.     {
  1533.         const char kDeleteButton = 0x08;
  1534.         char key = event->message & charCodeMask;
  1535.         if ( key == kDeleteButton )
  1536.         {
  1537.             if ( isDraftsDlog )
  1538.             {
  1539.                 *itemHit = kDraftsDeleteBtn;
  1540.                 result = kODTrue;
  1541.             }
  1542.             else
  1543.             {
  1544.                 *itemHit = kDeleteDraftsDeleteBtn;
  1545.                 result = kODTrue;
  1546.             }
  1547.         }
  1548.     }
  1549.     if ( result )
  1550.         FlashButtonItem( dialog, *itemHit );
  1551.     else
  1552.     {
  1553.         if ( isDraftsDlog )
  1554.             result = DraftDlgFilterProc( dialog, event, itemHit );
  1555.         else
  1556.             result = ODDialogFilterProc( dialog, event, itemHit );
  1557.     }
  1558.  
  1559.     return result;
  1560. }
  1561.  
  1562. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  1563.         Boolean hasContent )
  1564. {
  1565.     short openHiliteState = hasContent? kDraftsActiveControl : 255;
  1566.     short deleteHiliteState
  1567.             = hasContent && hasWriteAccess? kDraftsActiveControl : 255;
  1568.  
  1569.     short ignoreT;
  1570.     ControlHandle control;
  1571.     Rect ignoreR;
  1572.  
  1573.     GetDialogItem( dlog, kDraftsDeleteBtn, &ignoreT,
  1574.             (Handle*)&control, &ignoreR );
  1575.     HiliteControl( control, deleteHiliteState);
  1576.     SetControlReference( control, deleteHiliteState );
  1577.  
  1578.     GetDialogItem( dlog, kDraftsOpenBtn, &ignoreT, (Handle*)&control,
  1579.             &ignoreR );
  1580.     HiliteControl( control, openHiliteState );
  1581.     SetControlReference( control, openHiliteState );
  1582. }
  1583.  
  1584. static void AddRows( ListHandle listH, short startIndex, short numToAdd )
  1585. {
  1586.     char aByte = 'a' ;
  1587.     Cell newCell;
  1588.     newCell.h = 0;
  1589.     short finalIndex = startIndex + numToAdd;
  1590.     while ( startIndex < finalIndex )
  1591.     {
  1592.         LAddRow(1, startIndex, listH);
  1593.         newCell.v = startIndex++;
  1594.         LSetCell( &aByte, 1, newCell, listH );
  1595.     }
  1596. }
  1597.  
  1598. //------------------------------------------------------------------------------
  1599. // Callback to let LDEF communicate with DraftWindow
  1600. //------------------------------------------------------------------------------
  1601.  
  1602. void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  1603.         ODSShort row, const Rect* listItemRect)
  1604. {
  1605.     DraftInfoRec *dir = callbackInfo->dir ;
  1606.     WASSERT(dir);
  1607.  
  1608.     TRY    // much of what follows can't throw, but some of it can, so I'm
  1609.         // making this thing cover nearly all of the routine.  The overhead
  1610.         // is paid but once anyway.
  1611.  
  1612.         dir = GetNthRow( dir, row );
  1613.         WASSERT( dir );
  1614.     
  1615.         DialogPtr dlog = callbackInfo->dialog;
  1616.         Rect localRect;
  1617.         localRect.top = listItemRect->top;
  1618.         localRect.bottom = listItemRect->bottom;
  1619.         
  1620.         ODIText* fourStrings[kNumColumns];
  1621.         fourStrings[kCommentsColumnIndex] = dir->GetComment();
  1622.         ODBoolean isFullType = dir->GetDIRType() == kDIRTypeFull;
  1623.         if ( isFullType )
  1624.         {
  1625.             fourStrings[0] = ((FullDraftInfoRec*)dir)->GetModifiedBy();
  1626.             fourStrings[1] = ((FullDraftInfoRec*)dir)->GetNumberString();
  1627.             fourStrings[2] = ((FullDraftInfoRec*)dir)->GetCreated();
  1628.         }
  1629.         else
  1630.         {
  1631.             WASSERT(dir->GetDIRType() == kDIRTypeDummy);
  1632.             fourStrings[0] = fourStrings[1] = fourStrings[2] = kODNULL;
  1633.         }
  1634.     
  1635.         // Determination whether a comment is too long to be drawn in a single
  1636.         // line is done lazily: it's put off until now, where the DrawITextInDlogBox
  1637.         // function get the necessary information as part of its job.  So now, in
  1638.         // addition to drawing the strings, we need to save off that information.
  1639.     
  1640.         ODBoolean truncatedThisComment = kODFalse;        // default values
  1641.         ODBoolean mayWantToTruncate;
  1642.         for ( short index = 0; index < kNumColumns; ++index )
  1643.         {
  1644.             localRect.left = callbackInfo->rectEnds[index].left;
  1645.             localRect.right = callbackInfo->rectEnds[index].right;
  1646.             if ( fourStrings[index] )
  1647.             {
  1648.                 // don't try to truncate if guaranteed short enough already.  This fixes
  1649.                 // TextEdit's ignoring of training spaces when calculating line breaks.
  1650.                 // If this is a dummy record, we *know* that the comment will fit; otherwise
  1651.                 // check if this is an expanded full record's comments column, in which
  1652.                 // case we've already clipped the comments to fit.
  1653.                 mayWantToTruncate = isFullType &&
  1654.                         ((index != kCommentsColumnIndex)
  1655.                         || !(((FullDraftInfoRec*)dir)->IsExpanded()));
  1656.                 ODBoolean truncatedThisColumn =
  1657.                         DrawITextInDlogBox( fourStrings[index],
  1658.                         &localRect, dlog, mayWantToTruncate );
  1659.                 if ( index == kCommentsColumnIndex )
  1660.                     truncatedThisComment =
  1661.                             truncatedThisComment || truncatedThisColumn;
  1662.             }
  1663.         }
  1664.         if ( truncatedThisComment )
  1665.         {
  1666.             WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1667.             WASSERT( ((FullDraftInfoRec*)dir)->IsExpanded() == kODFalse );
  1668.             // record that this entry has a too-long comment
  1669.             ((FullDraftInfoRec*)dir)->SetCanExpand();
  1670.         }
  1671.     
  1672.         // now decide whether we need to draw the expansion icon and draw
  1673.         // the right one.
  1674.         
  1675.         if ( isFullType && ((FullDraftInfoRec*)dir)->CanExpand() )
  1676.         {
  1677.             localRect.left = callbackInfo->arrowEnds.left;
  1678.             localRect.right = callbackInfo->arrowEnds.right;
  1679.     
  1680.             ODSLong savedRefNum;
  1681.             BeginUsingLibraryResources(savedRefNum);        
  1682.             OSErr err = PlotIconID( &localRect, atNone, ttNone,
  1683.                     ((FullDraftInfoRec*)dir)->IsExpanded() ?
  1684.                     kDWOpenTriangleResID : kDWClosedTriangleResID );
  1685.             EndUsingLibraryResources(savedRefNum);
  1686.         }
  1687.  
  1688.         // finally, hilite if this record is [part of] the selection
  1689.         if ( dir->ShouldHilite() )
  1690.         {
  1691.             short oldPenMode = dlog->pnMode;
  1692.             PenMode( hilitetransfermode );
  1693.             PaintRect( listItemRect ) ;
  1694.             PenMode( oldPenMode );
  1695.         }
  1696.  
  1697.     CATCH_ALL
  1698.         WARN( "ignoring error in DrawDWUserStrings" );
  1699.     ENDTRY
  1700. }
  1701.  
  1702.  
  1703.  
  1704.  
  1705.